using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using JKFrame;

/// <summary>
/// A*寻路管理器
/// </summary>
public class AStarMgr : Singleton<AStarMgr>
{
    public int mapW;
    public int mapH;

    // 所有格子的容器
    public AStarNode[,] nodes;
    // 开启列表
    private List<AStarNode> openList = new List<AStarNode>(); 
    // 关闭列表
    private List<AStarNode> closeList = new List<AStarNode>();

    /// <summary>
    /// 初始化
    /// </summary>
    /// <param name="w"></param>
    /// <param name="h"></param>
    public void InitMapInfo(int w, int h)
    {
        nodes = new AStarNode[w, h];

        mapW = w;
        mapH = h;
        for (int i = 0; i < w; ++i)
        {
            for (int j = 0; j < h; ++j)
            {
                //随机阻挡
                AStarNode node = new AStarNode(i, j, Random.Range(0, 100) < 80 ? E_Node_Type.Walk : E_Node_Type.Stop);
                nodes[i, j] = node;
            }
        }
    }

    public List<AStarNode> FindPath(Vector2 startPos, Vector3 endPos)
    {
        //判断两个点是否合法
        if (startPos.x < 0 || startPos.x >= mapW || startPos.y < 0 || startPos.y >= mapH ||
            endPos.x < 0 || endPos.x >= mapW || endPos.y < 0 || endPos.y >= mapH)
        {
            Debug.Log("起点或终点不合法");
            return null;
        }

        //判断不是阻挡格子
        AStarNode start = nodes[(int)startPos.x, (int)startPos.y];
        AStarNode end = nodes[(int)endPos.x, (int)endPos.y];
        if (start.type == E_Node_Type.Stop || end.type == E_Node_Type.Stop)
        {
            Debug.Log("起点或终点是阻挡格子");
            return null;
        }
        //清空开启和关闭列表
        openList.Clear();
        closeList.Clear();

        // 把开始点放入关闭列表中
        start.father = null;//结束条件，从终点回溯位置添加到路径集合
        start.g = 0;
        start.f = 0;
        start.h = 0;
        closeList.Add(start);


        while (true)
        {
            //计算周围的点的位置
            //FindNearlyNodeToOpenList(start.x - 1, start.y - 1, 1.4f, start, end); //左上
            FindNearlyNodeToOpenList(start.x, start.y - 1, 1f, start, end); //上
            //FindNearlyNodeToOpenList(start.x + 1, start.y - 1, 1.4f, start, end); //右上
            FindNearlyNodeToOpenList(start.x - 1, start.y, 1f, start, end); //左
            FindNearlyNodeToOpenList(start.x + 1, start.y, 1f, start, end); //右
           //FindNearlyNodeToOpenList(start.x - 1, start.y + 1, 1.4f, start, end); //左下
            FindNearlyNodeToOpenList(start.x, start.y + 1, 1f, start, end); //下
            //FindNearlyNodeToOpenList(start.x + 1, start.y + 1, 1.4f, start, end); //右下
            //死路判断
            if(openList.Count == 0)
            {
                //没有路径了
                Debug.Log("没有路径了");
                return null;
            }
            //选出f值最小的点
            openList.Sort(SortOpenList);
            //openList.Sort((a,b)=>a.f<b.f?1:-1);
            //放入关闭列表
            closeList.Add(openList[0]);
            //将新的起点持有
            start = openList[0];
            //从开启列表中删除
            openList.RemoveAt(0);

            if (start == end)
            {
                //找到了
                List<AStarNode> path = new List<AStarNode>();
                path.Add(end);
                while(end.father != null )
                {
                    path.Add(end.father);
                    end = end.father;
                }
                //列表反转
                path.Reverse();
                return path;
            }
        }
    }

    public int SortOpenList(AStarNode a, AStarNode b)
    {
        if (a.f > b.f)
        {
            return 1;
        }
        else if (a.f < b.f)
        {
            return -1;
        }
        else
        {
            return 0;
        }
    }

    /// <summary>
    /// 把临近的点放入开启列表
    /// </summary>
    /// <param name="x"></param>
    /// <param name="y"></param>
    private void FindNearlyNodeToOpenList(int x, int y, float g, AStarNode father, AStarNode end)
    {
        //边界判断
        if (x < 0 || x >= mapW || y < 0 || y >= mapH)
        {
            return;
        }
        //在范围内
        AStarNode node = nodes[x, y];
        //判断是否是阻挡格子
        if (node == null || node.type == E_Node_Type.Stop || closeList.Contains(node) || openList.Contains(node))
        {
            return;
        }
        //计算g,h,f值 f = g + h
        node.father = father;
        node.g = father.g + g;
        node.h = Mathf.Abs(end.x - node.x) + Mathf.Abs(end.y - node.y);
        node.f = node.g + node.h;
        //合法 存
        openList.Add(node);
    }
}
